<script lang="ts">
import { PropType, computed, h, nextTick, reactive, ref, watch } from 'vue'
import APopup from './APopup.vue'
import AScrollable from './AScrollable.vue'
import { PopModifier, PopPlacementType, PopupExposed, TriggerType } from '@/types'

interface PropsType {
    popShown?: boolean
    popPlacement: PopPlacementType
    popModifiers: PopModifier[]
    getPopModifiersFunc?: () => PopModifier[]
    useTargetWidth: boolean
    maxHeight?: number
    trigger: TriggerType
}
interface StateType {
    innerPopShown: boolean
}

export default {
    props: {
        popShown: {
            type: Boolean,
            default: undefined,
        },
        popPlacement: {
            type: String as PropType<PopPlacementType>,
            default: 'bottom'
        },
        popModifiers: {
            type: Array as PropType<PopModifier[]>,
            default: []
        },
        getPopModifiersFunc: {
            type: Function as PropType<() => PopModifier[]>,
            default: undefined
        },
        useTargetWidth: {
            type: Boolean,
            default: false,
        },
        maxHeight: {
            type: Number,
            default: undefined,
        },
        trigger: {
            type: String as PropType<TriggerType>,
            default: 'click'
        },
    },
    setup(props: PropsType, ctx) {
        const state = reactive<StateType>({
            innerPopShown: false,
        })
        const myPopShown = computed(() => {
            if (props.popShown !== undefined) {
                return props.popShown
            }
            return state.innerPopShown
        })

        watch(() => myPopShown.value, () => {
            if (myPopShown.value) {
                methods.onPopShown()
            }
        })

        const popupRef = ref<PopupExposed>()
        const methods = {
            showPop() {
                state.innerPopShown = true
                ctx.emit('update:popShown', true)
            },
            hidePop() {
                state.innerPopShown = false
                ctx.emit('update:popShown', false)
            },
            getTargetEl() {
                return popupRef.value?.getTargetEl()
            },
            getPopEl() {
                return popupRef.value?.getPopEl()
            },
            updatePopShown(value: boolean) {
                if (value) {
                    methods.showPop()
                } else {
                    methods.hidePop()
                }
            },
            onPopShown() {
                if (!props.useTargetWidth) {
                    return
                }
                nextTick(() => {
                    let popEl = methods.getPopEl()
                    if (!popEl) {
                        return
                    }

                    let targetEl = methods.getTargetEl()!
                    let targetRect = targetEl.getBoundingClientRect()
                    popEl.style.width = targetRect.width + 'px'
                })
            }
        }

        ctx.expose({
            getTargetEl: methods.getTargetEl,
            getPopEl: methods.getPopEl,
        })

        return () => {
            let popRender: any = undefined
            if (props.maxHeight && props.maxHeight > 0) {
                popRender = h(AScrollable, {
                    style: {
                        maxHeight: `${props.maxHeight}px`
                    },
                }, { default: ctx.slots.pop })
            } else {
                popRender = ctx.slots.pop!()
            }

            return h(APopup, {
                popShown: myPopShown.value,
                'onUpdate:popShown': (value: boolean) => methods.updatePopShown(value),
                popPlacement: props.popPlacement,
                popModifiers: props.popModifiers,
                getPopModifiersFunc: props.getPopModifiersFunc,
                trigger: props.trigger,
                escToClose: true,
                ref: popupRef
            }, {
                default: ctx.slots.default,
                pop: () => popRender
            })
        }
    }
}
</script>